// TLSConnection.cc
#include "TLSConnection.hpp"
#include <openssl/err.h>
#include <iostream>
#include <unistd.h>

TLSConnection::TLSConnection(SSL_CTX* ctx, int conn_fd)
    : ssl_(nullptr), fd_(conn_fd)
{
    ssl_ = SSL_new(ctx);
    if (!ssl_) {
        std::cerr << "SSL_new failed\n";
        throw std::runtime_error("SSL_new failed");
    }

    SSL_set_fd(ssl_, fd_); //将ssl和对应的通信套接字联系起来
}

TLSConnection::~TLSConnection() {
    if (ssl_) {
        SSL_shutdown(ssl_);
        SSL_free(ssl_);
    }
    if (fd_ >= 0) {
        close(fd_);
    }
}

bool TLSConnection::doHandshake(bool isServer) {
    int ret = isServer ? SSL_accept(ssl_) : SSL_connect(ssl_);
    if (ret <= 0) {
        std::cerr << "TLS handshake failed\n";
        ERR_print_errors_fp(stderr);
        return false;
    }
    return true;
}

int TLSConnection::read(char* buf, size_t len) {
    return SSL_read(ssl_, buf, static_cast<int>(len));
}

int TLSConnection::write(const char* buf, size_t len) {
    return SSL_write(ssl_, buf, static_cast<int>(len));
}


int TLSConnection::read(char* buf, size_t len, int* err_no) {
    *err_no = 0;  // 先清零

    int ret = SSL_read(ssl_, buf, static_cast<int>(len));
    if (ret > 0) {
        return ret;  // 读到数据
    }

    int ssl_err = SSL_get_error(ssl_, ret);
    switch (ssl_err) {
        case SSL_ERROR_WANT_READ:
        case SSL_ERROR_WANT_WRITE:
            *err_no = EAGAIN;  // 非阻塞下的“稍后重试”
            return -1;

        case SSL_ERROR_ZERO_RETURN:
            return 0;  // 连接已关闭

        case SSL_ERROR_SYSCALL:
            if (ret == 0) {
                return 0;  // 连接关闭
            } else if (ret == -1) {
                *err_no = errno;  // 系统调用错误
                return -1;
            }
        default:
            *err_no = ssl_err;  // OpenSSL内部错误码（非系统errno）
            return -1;
    }
}



int TLSConnection::write(const char* buf, size_t len, int* err_no) {
    *err_no = 0;

    int ret = SSL_write(ssl_, buf, static_cast<int>(len));
    if (ret > 0) {
        return ret;  // 成功写入
    }

    int ssl_err = SSL_get_error(ssl_, ret);
    switch (ssl_err) {
        case SSL_ERROR_WANT_READ:
        case SSL_ERROR_WANT_WRITE:
            *err_no = EAGAIN;  // 非阻塞操作，需要重试
            return -1;

        case SSL_ERROR_ZERO_RETURN:
            // 连接关闭
            return 0;

        case SSL_ERROR_SYSCALL:
            if (ret == 0) {
                return 0;  // 连接关闭
            } else if (ret == -1) {
                *err_no = errno;  // 系统调用错误
                return -1;
            }

        default:
            *err_no = ssl_err;  // 其他OpenSSL内部错误码
            return -1;
    }
}
